﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Threading;
using ExpenseSystem.Common;
using System.Data.SqlClient;
using ExpenseSystem.Common.BaseModel;

namespace ExpenseSystem.Lor
{
    public static class SqlProvider
    {
        static SqlProvider()
        {
            //LogHelper.Info("SqlProvider", "正在注册事务清理程序到线程池");
            /*bool result = ThreadPool.QueueUserWorkItem(KillTransaction);
            if (result)
            {
                LogHelper.Info("SqlProvider", "注册事务清理程序到线程池成功");
            }
            else
            {
                LogHelper.Error("SqlProvider", "注册事务清理程序到线程池失败");
            }*/
        }
        public static SqlConnection GetConnection()
        {
            SqlConnection connection = new SqlConnection();
            connection.ConnectionString = Variable.DB_CONN;
            return connection;
        }
        public static string CreateTransaction()
        {
            LogHelper.Info("SqlProvider", "正在创建事务...");
            SqlConnection connection = GetConnection();
            SqlTransaction tran = null;
            string key = "";
            try
            {
                connection.Open();
                tran = connection.BeginTransaction();
                key = tran.GetHashCode().ToString();
                TranRecord record = new TranRecord() { LastCall = DateTime.Now, Tran = tran };
                tranPool.Add(key, record);
                LogHelper.Info("SqlProvider", String.Format("创建事务成功！事务号[{0}]", key));
            }
            catch (Exception ex)
            {
                LogHelper.Error("SqlProvider", "创建事务失败，原因是:" + ex.Message);
            }
            return key;
        }
        public static SqlTransaction GetTransaction(string key)
        {
            if (String.IsNullOrWhiteSpace(key))
            {
                return null;
            }
            if (tranPool.ContainsKey(key))
            {
                TranRecord tranRecord = (TranRecord)tranPool[key];
                tranRecord.LastCall = DateTime.Now;
                LogHelper.Info("SqlProvider", String.Format("使用Tran={0}成功返回事务", key));
                return tranRecord.Tran;
            }
            LogHelper.Error("SqlProvider", String.Format("无法使用Tran={0}找到相应的事务", key));
            return null;
        }
        public static void CloseTransaction(string key)
        {
            CloseTransaction(key, true);
        }
        public static void CloseTransaction(string key, bool commit)
        {
            LogHelper.Info("SqlProvider", String.Format("尝试关闭Tran={0}的事务并{1}", key, commit ? "提交" : "回滚"));
            SqlTransaction tran = GetTransaction(key);
            if (tran == null)
            {
                LogHelper.Error("SqlProvider", String.Format("将要关闭的Tran={0}的事务不存在", key));
                return;
            }
            SqlConnection dbConnection = tran.Connection;
            try
            {
                if (commit)
                    tran.Commit();
                else
                    tran.Rollback();
                tranPool.Remove(key);
                LogHelper.Info("SqlProvider", String.Format("关闭Tran={0}的事务并{1}完成", key, commit ? "提交" : "回滚"));
            }
            catch (Exception ex)
            {
                LogHelper.Error("SqlProvider", String.Format("关闭的Tran={0}的事务失败，失败原因是{1}", key, ex.Message));
            }
            finally
            {
                if (dbConnection != null)
                    dbConnection.Close();
            }
        }
        public static MsSqlMaker<T> GetDbInstance<T>() where T : SuperModel, new()
        {
            return new MsSqlMaker<T>();
        }
        private static void KillTransaction(object arg)
        {
            while (true)
            {
                LogHelper.Info("SqlProvider", "清理程序KillTransaction已被激活");
                try
                {
                    IList<string> transWillKilled = new List<string>();
                    foreach (DictionaryEntry de in tranPool)
                    {
                        try
                        {
                            TranRecord tranRecord = de.Value as TranRecord;
                            if (tranRecord.LastCall.AddMilliseconds(Math.Abs(Variable.TRANS_TTL)) <= DateTime.Now)
                            {
                                tranRecord.Tran.Rollback();
                                transWillKilled.Add(de.Key.ToString());
                                LogHelper.Info("SqlProvider", String.Format("清理程序KillTransaction正在处理过期事务Trans=[{0}]，最后使用时间为{1}", de.Key.ToString(), tranRecord.LastCall));
                            }
                        }
                        catch (Exception ex)
                        {
                            LogHelper.Error("SqlProvider", String.Format("清理程序KillTransaction在处理Trans=[{0}]时捕获了异常，异常信息如下:{1}", de.Key, ex.Message));
                        }
                    }
                    foreach (string dieTran in transWillKilled)
                    {
                        LogHelper.Info("SqlProvider", String.Format("清理程序KillTransaction将Trans=[{0}]从系统中移除", dieTran));
                        tranPool.Remove(dieTran);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error("SqlProvider", "清理程序KillTransaction捕获了异常，异常信息如下:" + ex.Message);
                }
                Thread.Sleep(Variable.KILL_TRANS_PERIOD);
            }
        }
        private static Hashtable tranPool = Hashtable.Synchronized(new Hashtable());
        private class TranRecord
        {
            public DateTime LastCall { get; set; }
            public SqlTransaction Tran { get; set; }
        }
    }
}
